﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;

namespace WeatherComm
{
    /// <summary>
    /// EF——对象操作-辅助类
    /// </summary>
    /// <typeparam name="TDbContext"></typeparam>
    public class EfHelper<TDbContext> where TDbContext : DbContext, new()
    {
        private TDbContext _dbContext;

        /// <summary>
        /// 实例化DbContext
        /// </summary>
        /// <returns></returns>
        public TDbContext GetDBEntities()
        {
            _dbContext = _dbContext ?? new TDbContext();

            return _dbContext;
        }

        /// <summary>
        /// 添加数据到对象
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <param name="t">对象名</param>
        /// <returns>true/false</returns>
        public bool Add<T>(T t) where T : class
        {
            try
            {
                var sde = GetDBEntities();
                sde.Set<T>().Add(t);
                return sde.SaveChanges() > 0;
            }
            catch (Exception ex)
            {
                Log.WriteLog($@"添加数据失败：{ex}");
                return false;
            }
        }

        /// <summary>
        /// 根据条件查询对象并返回对象集合
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <param name="p">条件（为NULL则返回所有数据）</param>
        /// <param name="count">返回记录条数</param>
        /// <returns>对象集合list</returns>
        public IEnumerable<T> GetList<T>(Expression<Func<T, bool>> p = null, int count = 0) where T : class
        {
            var sde = GetDBEntities();
            if (count == 0)
            {
                return p == null ? sde.Set<T>() : sde.Set<T>().Where(p);
            }
            return p == null ? sde.Set<T>() : sde.Set<T>().Where(p).Take(count);

        }

        /// <summary>
        /// 根据条件查询一条对象
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <param name="p">条件（为NULL则返回表数据的默认第一行数据）</param>
        /// <returns>对象</returns>
        public T GetNow<T>(Expression<Func<T, bool>> p = null) where T : class
        {
            var sde = GetDBEntities();

            if (p == null)
                return sde.Set<T>().FirstOrDefault();

            return sde.Set<T>().Where(p).FirstOrDefault();
        }

        public int GetMaxPK<T>(IQueryable<T> query, string pkPropertyName)
        {

            var parameter = Expression.Parameter(typeof(T));
            var body = Expression.Property(parameter, pkPropertyName);
            var lambda = Expression.Lambda<Func<T, int>>(body, parameter);
            var result = query.Max(lambda);
            return result;
        }

        /// <summary>
        /// 根据条件获取临时对象，用于检测是否存在
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <param name="p">条件（为NULL则判断表数据是否存在）</param>
        /// <returns></returns>
        public bool Exists<T>(Expression<Func<T, bool>> p = null) where T : class
        {
            var sde = GetDBEntities();

            if (p == null)
                return sde.Set<T>().Any();

            return sde.Set<T>().Where(p).AsNoTracking().FirstOrDefault() != null;
        }

        /// <summary>
        /// 修改对象
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <param name="t">对象名称</param>
        /// <returns>true/false</returns>
        public bool Update<T>(T t) where T : class
        {
            try
            {
                var sde = GetDBEntities();
                var ent = sde.Entry<T>(t);
                ent.State = EntityState.Modified;
                var pi = t.GetType().GetProperties();
                foreach (var r in pi)
                {
                    var obj = r.GetValue(t);
                    ent.Property(r.Name).IsModified = true;
                }
                return sde.SaveChanges() > 0;
            }
            catch
            {
                //WriteLog($@"更新数据失败：{ex}");
                return false;
            }
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <param name="t">对象名</param>
        /// <returns>true/false</returns>
        public bool Delete<T>(T t) where T : class
        {
            try
            {
                var sde = GetDBEntities();
                var ent = sde.Entry(t);
                ent.State = EntityState.Deleted;
                return sde.SaveChanges() > 0;
            }
            catch
            {
                //WriteLog($@"删除数据失败：{ex}");
                return false;
            }
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <typeparam name="TKey">int</typeparam>
        /// <param name="select">查询字段</param>
        /// <param name="where">查询条件</param>
        /// <param name="order">排序字段</param>
        /// <param name="pageIndex">当前页</param>
        /// <param name="pageSize">查询数据条数</param>
        /// <param name="Total">总共多少页</param>
        /// <param name="orderby">排序</param>
        /// getPageData<T, int>(t => new { t.ID, t.Name }, t => t.ID < 20, t => t.ID, 1, 10, out Total)
        /// <returns></returns>
        public IEnumerable<dynamic> GetPageData<T, TKey>(Expression<Func<T, dynamic>> select, Expression<Func<T, bool>> where, Expression<Func<T, TKey>> order, int pageIndex, int pageSize, out int Total, string orderBy = "asc")
           where T : class
        {
            var sde = GetDBEntities();
            Total = sde.Set<T>().Where(where).Count();
            return orderBy == "desc" ? sde.Set<T>().Where(@where).OrderByDescending(order).Select(@select).Skip((pageIndex - 1) * pageSize).Take(pageSize)
                : sde.Set<T>().Where(@where).OrderBy(order).Select(@select).Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        /// <summary>
        /// 执行SQL语句（查询语句除外）
        /// </summary>
        /// <param name="sqlStr">SQL语句（INSERT、UPDATE、DELETE）</param>
        /// <param name="parameters">参数（可选）</param>
        /// <returns></returns>
        public int ExecuteSql(string sqlStr, params IDataParameter[] parameters)
        {
            var sqlList = sqlStr.Split(';').ToList();
            sqlList.ForEach(p =>
            {
                if (p.ToUpper().TrimStart().StartsWith("SELECT"))
                    throw new ArgumentException($@"{nameof(ExecuteSql)}不能为查询语句，请调用{nameof(SqlQuery)}方法", nameof(sqlStr));
            });

            var sde = GetDBEntities();
            return sde.Database.ExecuteSqlCommand(sqlStr, parameters);
        }

        /// <summary>
        /// 执行SQL语句查询
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="sqlStr">SQL语句（SELECT）</param>
        /// <param name="parameters">参数（可选）</param>
        /// <returns></returns>
        public IEnumerable<T> SqlQuery<T>(string sqlStr, params IDataParameter[] parameters)
        {
            if (sqlStr.Split(';').Length > 1) throw new ArgumentOutOfRangeException(nameof(sqlStr), @"只支持一条查询SQL语句");

            if (!sqlStr.ToUpper().TrimStart().StartsWith("SELECT"))
                throw new ArgumentException($@"{nameof(SqlQuery)}只能为查询语句", nameof(sqlStr));

            var sde = GetDBEntities();
            return sde.Database.SqlQuery<T>(sqlStr, parameters);
        }
    }
}
